package com.treasure.mall.biz.remote.quickpay.impl;

import com.github.binarywang.wxpay.bean.order.WxPayAppOrderResult;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.treasure.mall.biz.bo.quickpay.AppBizPackage;
import com.treasure.mall.biz.bo.quickpay.JsApiBizPackage;
import com.treasure.mall.biz.bo.quickpay.WechatPayConfig;
import com.treasure.mall.biz.config.wechat.WeChatConfig;
import com.treasure.mall.biz.entity.wechat.WechatConfigPO;
import com.treasure.mall.biz.remote.quickpay.dto.WxRefundDTO;
import com.treasure.mall.biz.remote.quickpay.dto.WxTradeOrderDTO;
import com.treasure.mall.biz.remote.quickpay.WechatPayService;
import com.treasure.mall.biz.service.core.wechat.WechatConfigService;
import com.treasure.mall.zbq.common.StringUtilsExt;
import com.treasure.mall.zbq.common.exception.ApiException;
import com.treasure.mall.zbq.common.ienum.order.OrderEnums;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 *
 * +---------------------------------------------------------
 * * @package: com.treasure.mall.biz.remote.quickpay
 * * @author: guomw (guomwchen@foxmail.com)
 * * @date: 2020/6/12 23:42
 * * @since: V1.0.0
 * +---------------------------------------------------------
 * 注意：本内容仅限于内部传阅，禁止外泄以及用于其他的商业目的
 * Copyright 2019-2022 com.treasure.mall.biz.remote.quickpay Inc. All rights reserved.
 */
@Slf4j
@Service
public class WechatPayServiceImpl implements WechatPayService {
    private static final String REFUND_SUCCESS = "SUCCESS";
    @Resource
    private WechatPayConfig payConfig;
    @Resource
    private WeChatConfig weChatConfig;

    @Override
    public WxPayService getWxPayService() {
        return payConfig.wxPayService();
    }

    @Override
    public Object JsApiBizPackage(WxTradeOrderDTO order, HttpServletRequest request) {
        boolean isApp = order.getTradeType() != null && order.getTradeType().getCode().equals(OrderEnums.TradeType.APP.getCode());
        WxPayService wxPayService = isApp ? payConfig.wxPayAppService() : payConfig.wxPayService();
        WxPayConfig wxPayConfig = wxPayService.getConfig();

        //2、统一支付请求构造
        WxPayUnifiedOrderRequest unifiedOrderRequest = new WxPayUnifiedOrderRequest();
        unifiedOrderRequest.setOutTradeNo(order.getOrderId());
        unifiedOrderRequest.setBody(order.getOrderName());
        unifiedOrderRequest.setTotalFee(yuanToFee(order.getSurplusAmount()));
        unifiedOrderRequest.setNotifyUrl(wxPayConfig.getNotifyUrl());
        if (!isApp) {
            unifiedOrderRequest.setTradeType(WxPayConstants.TradeType.JSAPI);
            unifiedOrderRequest.setSubAppId(weChatConfig.getMiniAppId());
            unifiedOrderRequest.setOpenid(order.getOpenId());
        } else {
            unifiedOrderRequest.setTradeType(order.getTradeType().getDesc());
        }
        unifiedOrderRequest.setAppid(wxPayConfig.getAppId());
        unifiedOrderRequest.setMchId(wxPayConfig.getMchId());
        //当前调起支付的小程序APPID
        unifiedOrderRequest.setSpbillCreateIp(StringUtilsExt.getClientIp(request));
        unifiedOrderRequest.setNonceStr(createRandomStr(16));
        unifiedOrderRequest.setAttach("");
        return isApp ? getResultByApp(unifiedOrderRequest, wxPayService) : getResultByJsApi(unifiedOrderRequest, wxPayService);
    }

    private Map<String, Object> getResultByApp(WxPayUnifiedOrderRequest unifiedOrderRequest, WxPayService wxPayService) {
        WxPayAppOrderResult result;
        try {
            result = wxPayService.createOrder(unifiedOrderRequest);
        } catch (Exception e) {
            log.error("createOrder wxPay exception", e);
            throw new IllegalStateException("createOrder wxPay exception");
        }
        AppBizPackage bizPackage = new AppBizPackage();
        bizPackage.setAppId(result.getAppId());
        bizPackage.setNonceStr(result.getNonceStr());
        bizPackage.setPack(result.getPackageValue());
        bizPackage.setSign(result.getSign());
        bizPackage.setPartnerId(result.getPartnerId());
        bizPackage.setPrepayId(result.getPrepayId());
        bizPackage.setTimeStamp(result.getTimeStamp());
        Map<String, Object> map = new HashMap<>();
        map.put("wechatMini", bizPackage);
        return map;
    }

    private Map<String, Object> getResultByJsApi(WxPayUnifiedOrderRequest unifiedOrderRequest, WxPayService wxPayService) {
        WxPayMpOrderResult result;
        try {
            result = wxPayService.createOrder(unifiedOrderRequest);
        } catch (Exception e) {
            log.error("createOrder wxPay exception", e);
            throw new IllegalStateException("createOrder wxPay exception");
        }
        JsApiBizPackage bizPackage = new JsApiBizPackage();
        bizPackage.setAppId(result.getAppId());
        bizPackage.setNonceStr(result.getNonceStr());
        bizPackage.setPack(result.getPackageValue());
        bizPackage.setPaySign(result.getPaySign());
        bizPackage.setSignType(result.getSignType());
        bizPackage.setTimeStamp(result.getTimeStamp());
        Map<String, Object> map = new HashMap<>();
        map.put("wechatMini", bizPackage);
        return map;
    }


    @Override
    public Boolean wxRefund(WxRefundDTO refundDTO) {
        //申请退款
        WxPayRefundRequest refundInfo = WxPayRefundRequest.newBuilder()
                .outTradeNo(refundDTO.getOrderNo())
                .outRefundNo(refundDTO.getRefundNo())
                .totalFee(yuanToFee(refundDTO.getTotalFee()))
                .refundFee(yuanToFee(refundDTO.getRefundFee()))
                .notifyUrl(payConfig.getRefundNotifyUrl())
                .build();

        try {
            WxPayRefundResult wxPayRefundResult = payConfig.wxPayService().refund(refundInfo);
            //判断退款信息是否正确
            if (REFUND_SUCCESS.equals(wxPayRefundResult.getReturnCode())
                    && REFUND_SUCCESS.equals(wxPayRefundResult.getResultCode())) {
                /**
                 * 系统内部业务逻辑
                 */
                return true;
            }
        } catch (WxPayException e) {
            log.error("微信退款接口错误信息", e);
        }
        return false;
    }

    /**
     * 1 块钱转为 100 分
     * 元转分
     *
     * @param bigDecimal 钱数目
     * @return 分
     */
    private int yuanToFee(BigDecimal bigDecimal) {
        return bigDecimal.multiply(new BigDecimal(100)).intValue();
    }

    /**
     * 时间
     *
     * @return 时间戳
     */
    private String createTimestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }

    /**
     * 得到随机字符串
     *
     * @return
     */
    public String createRandomStr(int digit) {
        String base = "abcdefghijklmnpqrstuvwxyz123456789";

        int baseLength = base.length();
        Random random = new Random();
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < digit; i++) {
            int number = random.nextInt(baseLength);
            stringBuilder.append(base.charAt(number));
        }
        return stringBuilder.toString();
    }
}
